export function initAligningGuidelines(canvas) {
  const ALIGNING_LINE_OFFSET = 5;
  const ALIGNING_LINE_MARGIN = 4; // 开始对齐的阈值
  const ALIGNING_LINE_LEVE_MARGIN = 6; // 开始解除对齐的阈值
  const ALIGNING_LINE_WIDTH = 1;
  const ALIGNING_LINE_COLOR = "rgb(0,255,0)";

  const ctx = canvas.getSelectionContext();
  let viewportTransform;
  let zoom = 1;
  let verticalLines = [];
  let horizontalLines = [];
  let lockedAxis = { x: null, y: null };

  function drawVerticalLine(coords) {
    const [x, y1, y2] = [
      coords.x + 0.5,
      Math.min(coords.y1, coords.y2),
      Math.max(coords.y1, coords.y2),
    ];
    drawLine(x, y1, x, y2);
  }

  function drawHorizontalLine(coords) {
    const [x1, x2, y] = [
      Math.min(coords.x1, coords.x2),
      Math.max(coords.x1, coords.x2),
      coords.y + 0.5,
    ];
    drawLine(x1, y, x2, y);
  }

  function drawLine(x1, y1, x2, y2) {
    ctx.save();
    ctx.lineWidth = ALIGNING_LINE_WIDTH;
    ctx.strokeStyle = ALIGNING_LINE_COLOR;
    ctx.beginPath();
    ctx.moveTo(
      x1 * zoom + viewportTransform[4],
      y1 * zoom + viewportTransform[5]
    );
    ctx.lineTo(
      x2 * zoom + viewportTransform[4],
      y2 * zoom + viewportTransform[5]
    );
    ctx.stroke();
    ctx.restore();
  }

  function isInRange(value1, value2) {
    return Math.abs(value1 - value2) <= ALIGNING_LINE_MARGIN;
  }

  function isInteractiveObject(object) {
    return object.selectable && object.evented && object.type === "image";
  }

  function getObjectBounds(object) {
    const center = object.getCenterPoint();
    const boundingRect = object.getBoundingRect();
    const height = boundingRect.height / viewportTransform[3];
    const width = boundingRect.width / viewportTransform[0];
    return { center, left: center.x, top: center.y, height, width };
  }

  // 坐标吸附函数
  function snapCoordinate(current, target) {
    const diff = current - target;
    return Math.abs(diff) <= ALIGNING_LINE_MARGIN ? target : current;
  }

  function handleAlignment(activeObject, otherObject) {
    if (!isInteractiveObject(otherObject)) {
      return { verticalInTheRange: false, horizontalInTheRange: false };
    }

    const activeBounds = getObjectBounds(activeObject);
    const otherBounds = getObjectBounds(otherObject);
    let verticalInTheRange = false;
    let horizontalInTheRange = false;

    // 存储候选对齐位置
    const candidatePositions = {
      x: [],
      y: [],
    };

    const alignmentRules = [
      // 右边缘对齐左边缘
      {
        check: () =>
          isInRange(
            activeBounds.left + activeBounds.width / 2,
            otherBounds.left - otherBounds.width / 2
          ),
        line: () => ({
          x: otherBounds.left - otherBounds.width / 2,
          y1:
            Math.min(
              otherBounds.top - otherBounds.height / 2,
              activeBounds.top - activeBounds.height / 2
            ) - ALIGNING_LINE_OFFSET,
          y2:
            Math.max(
              otherBounds.top + otherBounds.height / 2,
              activeBounds.top + activeBounds.height / 2
            ) + ALIGNING_LINE_OFFSET,
        }),
        setPosition: () => {
          const targetX =
            otherBounds.left - otherBounds.width / 2 - activeBounds.width / 2;
          candidatePositions.x.push(targetX);
          activeObject.setPositionByOrigin(
            new fabric.Point(targetX, activeBounds.top),
            "center",
            "center"
          );
        },
      },
      // 左边缘对齐右边缘
      {
        check: () =>
          isInRange(
            activeBounds.left - activeBounds.width / 2,
            otherBounds.left + otherBounds.width / 2
          ),
        line: () => ({
          x: otherBounds.left + otherBounds.width / 2,
          y1:
            Math.min(
              otherBounds.top - otherBounds.height / 2,
              activeBounds.top - activeBounds.height / 2
            ) - ALIGNING_LINE_OFFSET,
          y2:
            Math.max(
              otherBounds.top + otherBounds.height / 2,
              activeBounds.top + activeBounds.height / 2
            ) + ALIGNING_LINE_OFFSET,
        }),
        setPosition: () => {
          const targetX =
            otherBounds.left + otherBounds.width / 2 + activeBounds.width / 2;
          candidatePositions.x.push(targetX);
          activeObject.setPositionByOrigin(
            new fabric.Point(targetX, activeBounds.top),
            "center",
            "center"
          );
        },
      },
      // 上边缘对齐下边缘
      {
        check: () =>
          isInRange(
            otherBounds.top + otherBounds.height / 2,
            activeBounds.top - activeBounds.height / 2
          ),
        line: () => ({
          y: otherBounds.top + otherBounds.height / 2,
          x1:
            Math.min(
              otherBounds.left - otherBounds.width / 2,
              activeBounds.left - activeBounds.width / 2
            ) - ALIGNING_LINE_OFFSET,
          x2:
            Math.max(
              otherBounds.left + otherBounds.width / 2,
              activeBounds.left + activeBounds.width / 2
            ) + ALIGNING_LINE_OFFSET,
        }),
        setPosition: () => {
          const targetY =
            otherBounds.top + otherBounds.height / 2 + activeBounds.height / 2;
          candidatePositions.y.push(targetY);
          activeObject.setPositionByOrigin(
            new fabric.Point(activeBounds.left, targetY),
            "center",
            "center"
          );
        },
      },
      // 下边缘对齐上边缘
      {
        check: () =>
          isInRange(
            otherBounds.top - otherBounds.height / 2,
            activeBounds.top + activeBounds.height / 2
          ),
        line: () => ({
          y: otherBounds.top - otherBounds.height / 2,
          x1:
            Math.min(
              otherBounds.left - otherBounds.width / 2,
              activeBounds.left - activeBounds.width / 2
            ) - ALIGNING_LINE_OFFSET,
          x2:
            Math.max(
              otherBounds.left + otherBounds.width / 2,
              activeBounds.left + activeBounds.width / 2
            ) + ALIGNING_LINE_OFFSET,
        }),
        setPosition: () => {
          const targetY =
            otherBounds.top - otherBounds.height / 2 - activeBounds.height / 2;
          candidatePositions.y.push(targetY);
          activeObject.setPositionByOrigin(
            new fabric.Point(activeBounds.left, targetY),
            "center",
            "center"
          );
        },
      },
      // 水平中心线对齐
      {
        check: () => isInRange(otherBounds.left, activeBounds.left),
        line: () => ({
          x: otherBounds.left,
          y1:
            Math.min(
              otherBounds.top - otherBounds.height / 2,
              activeBounds.top - activeBounds.height / 2
            ) - ALIGNING_LINE_OFFSET,
          y2:
            Math.max(
              otherBounds.top + otherBounds.height / 2,
              activeBounds.top + activeBounds.height / 2
            ) + ALIGNING_LINE_OFFSET,
        }),
        setPosition: () => {
          candidatePositions.x.push(otherBounds.left);
          activeObject.setPositionByOrigin(
            new fabric.Point(otherBounds.left, activeBounds.top),
            "center",
            "center"
          );
        },
      },
      // 左边缘对齐
      {
        check: () =>
          isInRange(
            otherBounds.left - otherBounds.width / 2,
            activeBounds.left - activeBounds.width / 2
          ),
        line: () => ({
          x: otherBounds.left - otherBounds.width / 2,
          y1:
            Math.min(
              otherBounds.top - otherBounds.height / 2,
              activeBounds.top - activeBounds.height / 2
            ) - ALIGNING_LINE_OFFSET,
          y2:
            Math.max(
              otherBounds.top + otherBounds.height / 2,
              activeBounds.top + activeBounds.height / 2
            ) + ALIGNING_LINE_OFFSET,
        }),
        setPosition: () => {
          const targetX =
            otherBounds.left - otherBounds.width / 2 + activeBounds.width / 2;
          candidatePositions.x.push(targetX);
          activeObject.setPositionByOrigin(
            new fabric.Point(targetX, activeBounds.top),
            "center",
            "center"
          );
        },
      },
      // 右边缘对齐
      {
        check: () =>
          isInRange(
            otherBounds.left + otherBounds.width / 2,
            activeBounds.left + activeBounds.width / 2
          ),
        line: () => ({
          x: otherBounds.left + otherBounds.width / 2,
          y1:
            Math.min(
              otherBounds.top - otherBounds.height / 2,
              activeBounds.top - activeBounds.height / 2
            ) - ALIGNING_LINE_OFFSET,
          y2:
            Math.max(
              otherBounds.top + otherBounds.height / 2,
              activeBounds.top + activeBounds.height / 2
            ) + ALIGNING_LINE_OFFSET,
        }),
        setPosition: () => {
          const targetX =
            otherBounds.left + otherBounds.width / 2 - activeBounds.width / 2;
          candidatePositions.x.push(targetX);
          activeObject.setPositionByOrigin(
            new fabric.Point(targetX, activeBounds.top),
            "center",
            "center"
          );
        },
      },
      // 垂直中心线对齐
      {
        check: () => isInRange(otherBounds.top, activeBounds.top),
        line: () => ({
          y: otherBounds.top,
          x1:
            Math.min(
              otherBounds.left - otherBounds.width / 2,
              activeBounds.left - activeBounds.width / 2
            ) - ALIGNING_LINE_OFFSET,
          x2:
            Math.max(
              otherBounds.left + otherBounds.width / 2,
              activeBounds.left + activeBounds.width / 2
            ) + ALIGNING_LINE_OFFSET,
        }),
        setPosition: () => {
          candidatePositions.y.push(otherBounds.top);
          activeObject.setPositionByOrigin(
            new fabric.Point(activeBounds.left, otherBounds.top),
            "center",
            "center"
          );
        },
      },
      // 上边缘对齐
      {
        check: () =>
          isInRange(
            otherBounds.top - otherBounds.height / 2,
            activeBounds.top - activeBounds.height / 2
          ),
        line: () => ({
          y: otherBounds.top - otherBounds.height / 2,
          x1:
            Math.min(
              otherBounds.left - otherBounds.width / 2,
              activeBounds.left - activeBounds.width / 2
            ) - ALIGNING_LINE_OFFSET,
          x2:
            Math.max(
              otherBounds.left + otherBounds.width / 2,
              activeBounds.left + activeBounds.width / 2
            ) + ALIGNING_LINE_OFFSET,
        }),
        setPosition: () => {
          const targetY =
            otherBounds.top - otherBounds.height / 2 + activeBounds.height / 2;
          candidatePositions.y.push(targetY);
          activeObject.setPositionByOrigin(
            new fabric.Point(activeBounds.left, targetY),
            "center",
            "center"
          );
        },
      },
      // 下边缘对齐
      {
        check: () =>
          isInRange(
            otherBounds.top + otherBounds.height / 2,
            activeBounds.top + activeBounds.height / 2
          ),
        line: () => ({
          y: otherBounds.top + otherBounds.height / 2,
          x1:
            Math.min(
              otherBounds.left - otherBounds.width / 2,
              activeBounds.left - activeBounds.width / 2
            ) - ALIGNING_LINE_OFFSET,
          x2:
            Math.max(
              otherBounds.left + otherBounds.width / 2,
              activeBounds.left + activeBounds.width / 2
            ) + ALIGNING_LINE_OFFSET,
        }),
        setPosition: () => {
          const targetY =
            otherBounds.top + otherBounds.height / 2 - activeBounds.height / 2;
          candidatePositions.y.push(targetY);
          activeObject.setPositionByOrigin(
            new fabric.Point(activeBounds.left, targetY),
            "center",
            "center"
          );
        },
      },
    ];

    alignmentRules.forEach((rule) => {
      if (rule.check()) {
        if (rule.line().x) {
          verticalInTheRange = true;
          verticalLines.push(rule.line());
        } else {
          horizontalInTheRange = true;
          horizontalLines.push(rule.line());
        }
        rule.setPosition();
      }
    });

    // 执行坐标吸附
    if (candidatePositions.x.length > 0) {
      const currentX = activeBounds.left;
      const nearestX = candidatePositions.x.reduce((prev, curr) =>
        Math.abs(curr - currentX) < Math.abs(prev - currentX) ? curr : prev
      );
      activeObject.set({ left: snapCoordinate(currentX, nearestX) });
      lockedAxis.x = nearestX; // 记录锁定位置
    }

    if (candidatePositions.y.length > 0) {
      const currentY = activeBounds.top;
      const nearestY = candidatePositions.y.reduce((prev, curr) =>
        Math.abs(curr - currentY) < Math.abs(prev - currentY) ? curr : prev
      );
      activeObject.set({ top: snapCoordinate(currentY, nearestY) });
      lockedAxis.y = nearestY; // 记录锁定位置
    }

    return { verticalInTheRange, horizontalInTheRange };
  }

  canvas.on("object:moving", function (e) {
    const activeObject = e.target;
    const canvasObjects = canvas
      .getObjects()
      .filter((obj) => isInteractiveObject(obj) && obj !== activeObject);

    // 计算考虑缩放后的实际阈值
    const actualThreshold = ALIGNING_LINE_LEVE_MARGIN / zoom;

    // 应用坐标锁定前先检测移动距离
    if (lockedAxis.x !== null) {
      const deltaX = Math.abs(activeObject.left - lockedAxis.x);
      if (deltaX > actualThreshold) {
        lockedAxis.x = null; // 超过阈值解除X轴锁定
      } else {
        activeObject.set({ left: lockedAxis.x });
      }
    }

    if (lockedAxis.y !== null) {
      const deltaY = Math.abs(activeObject.top - lockedAxis.y);
      if (deltaY > actualThreshold) {
        lockedAxis.y = null; // 超过阈值解除Y轴锁定
      } else {
        activeObject.set({ top: lockedAxis.y });
      }
    }

    let totalVertical = false;
    let totalHorizontal = false;

    canvasObjects.forEach((object) => {
      const { verticalInTheRange, horizontalInTheRange } = handleAlignment(
        activeObject,
        object
      );
      totalVertical ||= verticalInTheRange;
      totalHorizontal ||= horizontalInTheRange;
    });

    // 清除未使用的锁定轴
    if (!totalHorizontal) lockedAxis.y = null;
    if (!totalVertical) lockedAxis.x = null;
  });

  canvas.on("mouse:down", () => {
    viewportTransform = canvas.viewportTransform;
    zoom = canvas.getZoom();
    lockedAxis = { x: null, y: null }; // 重置锁定
  });

  canvas.on("before:render", () => canvas.clearContext(canvas.contextTop));
  canvas.on("after:render", () => {
    verticalLines.forEach(drawVerticalLine);
    horizontalLines.forEach(drawHorizontalLine);
    verticalLines.length = horizontalLines.length = 0;
  });

  canvas.on("mouse:up", () => {
    verticalLines.length = horizontalLines.length = 0;
    lockedAxis = { x: null, y: null }; // 释放锁定
    canvas.renderAll();
  });
}
